from flask import Blueprint, abort, request, make_response, redirect, render_template, url_for, session, flash
from wiki.databases import QueueWikiPostDB, WikiPostDB, UserDB, db
from wiki.utils import nocache, login_required, redirect_back, add_wiki, edit_wiki, macro_compiler
from wiki import app
from bs4 import BeautifulSoup
from re import sub
from json import dumps, loads
from flask_babel import gettext
from time import strftime
from random import choice
from os.path import join
from hashlib import sha224
from datetime import datetime, timedelta
from urllib.parse import urlsplit

wiki = Blueprint('wiki', __name__)

@wiki.route('/')
@nocache
def index():
	if app.config.get('FRONT_PAGE'):
		frontpage = WikiPostDB.query.filter_by(default_lang=session['lang'], url=gettext(app.config['FRONT_PAGE'])).first()
		if frontpage:
			content = macro_compiler(frontpage.content, 'macros.html')
			return render_template('wiki/index.html', content=content, len=len, sub=sub, frontpage=True)
	query = WikiPostDB.query.filter_by(default_lang=session['lang']).all()
	return render_template('wiki/index.html', query=query, len=len, sub=sub)

@wiki.route('/random/')
@nocache
def random():
	query = WikiPostDB.query.filter_by(default_lang=session['lang']).all()
	if len(query) <= 0:
		return abort(404)
	else:
		return redirect(url_for('wiki.post', post=choice(query).url))

@wiki.route('/search/', methods=['GET'])
@nocache
def search():
	if request.method == 'GET':
		if request.args.get('srch-term'):
			if request.method == 'GET':
				addressSearch = WikiPostDB.query.filter(WikiPostDB.address.contains( \
					request.args.get('srch-term')+'%')).filter_by(default_lang=session['lang']).all()
				contentSearch = WikiPostDB.query.filter(WikiPostDB.content.contains( \
					request.args.get('srch-term')+'%')).filter_by(default_lang=session['lang']).all()
				result = set(addressSearch + contentSearch)
				return render_template('wiki/list.html', sub=sub, query=result, title=gettext('Search'))
			else:
				return abort(404)
		else:
			return abort(404)
	else:
		return abort(404)

@wiki.route('/sitemap.xml', methods=['GET'])
def sitemap():
	"""Generate sitemap.xml. Makes a list of urls and date modified."""
	try:
		pages=[]
		ten_days_ago=(datetime.now() - timedelta(days=7)).date().isoformat()
		for rule in app.url_map.iter_rules():
			if 'GET' in rule.methods and len(rule.arguments)==0:
				pages.append([str(rule.rule),ten_days_ago])
		for post in WikiPostDB.query.all():
			pages.append([url_for('wiki.post', post=post.url, lang=post.default_lang), ten_days_ago])
		sitemap_xml = render_template('sitemap.xml', pages=pages, join=join)
		response= make_response(sitemap_xml)
		response.headers['Content-Type'] = 'application/xml'    
		return response
	except Exception as e:
		return 'error'

@wiki.route('/lang', methods=['GET'])
def langchanger():
	if request.method == 'GET':
		session['lang'] = request.args.get('lang')
		try:
			if request.referrer is not None:
				return redirect(urlsplit(request.referrer).path.split('/')[1])
			else:
				return redirect(url_for('wiki.index'))
		except Exception:
			return redirect(url_for('wiki.index'))				
	else:
		return abort(404)

@wiki.route('/login/', methods=['GET', 'POST'])
@nocache
@login_required(status=False)
def login():
	if request.method == 'POST':
		try:
			query = UserDB.query.filter_by(email=request.form['email']).first()
			if request.form['email'] == query.email and \
			 sha224(request.form['password'].encode('utf-8')).hexdigest() == query.password:
				session['logged_in'] = True
				session.permanent = True
				session['current_user'] = {'username':query.username, 'id':query.Id, 
										   'fullname':query.fullname, 'description':query.description, 
										   'email':query.email, 'privilege':query.privilege}
				return redirect(url_for('wiki.index'))
			else:
				flash('Error')
				return redirect(url_for('wiki.login'))
		except Exception:
			flash('Error')
			return redirect(url_for('wiki.login'))	
	else:
		return render_template('wiki/login.html')

@wiki.route('/logout/')
@nocache
@login_required()
def logout():
	session['logged_in'] = False
	return redirect(url_for('wiki.index'))

@wiki.route('/signup/', methods=['GET', 'POST'])
@nocache
@login_required(status=False)
def signup():
	if request.method == 'POST':
		emailQuery = UserDB.query.filter_by(email=request.form['email']).all()
		usernameQuery = UserDB.query.filter_by(username=request.form['username']).all()
		if len(emailQuery) >= 1 or len(usernameQuery) >= 1:
			flash('Error')
			return redirect(url_for('wiki.signup'))
		else:
			newQuery = UserDB(username=request.form['username'], email=request.form['email'], 
				              password=sha224(request.form['password'].encode('utf-8')).hexdigest(), fullname=request.form['fullname'], 
				              description=request.form['description'], privilege='user')
			session.permanent = True
			db.session.add(newQuery)
			db.session.commit()
			flash('SignUpSuccess')
			return redirect(url_for('wiki.index'))
	else:
		return render_template('wiki/signup.html')

@wiki.route('/u/')
@nocache
def users():
	query = UserDB.query.all()
	return render_template('wiki/users.html', sub=sub, query=query)

@wiki.route('/u/<username>/')
@nocache
def user_profile(username):
	query = UserDB.query.filter_by(username=username).first_or_404()
	posts = WikiPostDB.query.filter_by(creator_id=query.Id, default_lang=session['lang']).all()
	return render_template('wiki/profile.html', query=query, posts=posts, sub=sub, len=len)

@wiki.route('/u/<username>/edit', methods=['GET'])
@nocache
@login_required()
def edit_user(username):
	if request.method == 'GET':
		query = UserDB.query.filter_by(username=username).first_or_404()
		if int(session.get('current_user')['id']) == int(query.Id):
			try:
				searchQuery = UserDB.query.filter_by(email=request.args.get('email')).all()
				for account in searchQuery:
					if account.username != query.username:
						flash('Error')
						return redirect(url_for('wiki.profile', username=session.get('current_user')['username']))
				query.fullname = request.args.get('fullname')
				query.email = request.args.get('email')
				query.description = request.args.get('description')
				db.session.commit()
				return redirect(url_for('wiki.user_profile', username=session.get('current_user')['username']))
			except Exception:
				return abort(404)
		else:
			return abort(403)	
	else:	
		return abort(404)

@wiki.route('/u/<username>/delete', methods=['GET'])
@nocache
@login_required()
def delete_user(username):
	if request.method == 'GET':
		query = UserDB.query.filter_by(username=username).first_or_404()
		if int(session.get('current_user')['id']) == int(query.Id):
			try:
				if app.config['ROOT_USER']['username'] != query.username:				
					db.session.delete(query)
					db.session.commit()
					session['logged_in'] = False
					return redirect(url_for('wiki.index'))
				else:
					return abort(403)
			except Exception:
				return abort(404)
		else:
			return abort(403)	
	else:	
		return abort(404)

@wiki.route('/perview', methods=['POST'])
@nocache
@login_required()
def perview():
	if request.method == 'POST':
		content = macro_compiler(request.form['content'], 'macros.html')
		soup = BeautifulSoup(content,'html.parser')
		for header in soup.findAll(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']):
			header['id'] = header.text
		return render_template('wiki/perview.html', content=soup, address=request.form['post-header'], 
							   headerList=soup.findAll(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']), int=int)
	else:
		return abort(404)

@wiki.route('/add/', methods=['GET', 'POST'])
@nocache
@login_required()
def add_post():
	if request.method == 'POST':
		url = sub('[/?]', '', sub('[ +]', '-', request.form['post-header']))
		url = url[:-1] if url.endswith('-') else url
		if session['current_user']['privilege'] == 'admin':
			redirect_url = url_for('wiki.post', post=url)
		elif session['current_user']['privilege'] == 'user':
			redirect_url = url_for('wiki.index')
		return add_wiki(url=url, address=request.form['post-header'], 
					    content=request.form['content'], redirect_url=redirect_url, 
					    error_redirect=url_for('wiki.add_post'), privilege=session['current_user']['privilege'], 
					    lang=session['lang'])
	else:
		return render_template('wiki/post_action.html', mode='add')

@wiki.route('/p/<post>/')
@nocache
def post(post):
	query = WikiPostDB.query.filter_by(url=post, default_lang=session['lang']).first_or_404()
	content = macro_compiler(query.content, 'macros.html')	
	soup = BeautifulSoup(content, 'html.parser')
	return render_template('wiki/post.html', query=query, 
		                   headerList=soup.findAll(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']), 
		                   sub=sub, loads=loads, int=int, content=soup)

@wiki.route('/p/<post>/edit/', methods=['GET', 'POST'])
@nocache
@login_required()
def edit_post(post):
	if request.method == 'POST':
		url = sub('[/?]', '', sub('[ +]', '-', request.form['post-header']))
		url = url[:-1] if url.endswith('-') else url
		if session['current_user']['privilege'] == 'admin':			
			redirect_url = url_for('wiki.post', post=url)
		elif session['current_user']['privilege'] == 'user':
			redirect_url = url_for('wiki.index')
		return edit_wiki(Id=request.form['id'], url=url, 
			             address=request.form['post-header'], content=request.form['content'], 
			             redirect_url=redirect_url, error_redirect=request.referrer, 
			             privilege=session['current_user']['privilege'], lang=session['lang'])		
	else:
		query = WikiPostDB.query.filter_by(url=post, default_lang=session['lang']).first_or_404()
		return render_template('wiki/post_action.html', query=query, mode='edit')

@wiki.route('/p/<post>/delete/')
@nocache
@login_required(status=True, privilege='admin')
def delete_post(post):
	query = WikiPostDB.query.filter_by(url=post, default_lang=session['lang']).first_or_404()
	db.session.delete(query)
	db.session.commit()
	return redirect(url_for('wiki.index'))

@wiki.route('/p/')
@nocache
def posts():
	query = WikiPostDB.query.filter_by(default_lang=session['lang']).all()
	return render_template('wiki/list.html', query=query, sub=sub, title=gettext('All Posts'))